// 
//  UserInfo.cs
//  
//  Author:
//       Ray Shaw <demogodyou@gmail.com>
// 
//  Copyright (c) 2009 Ray Shaw(xiaolei)
// 
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//  
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// 

//------------------------------------------------------------------------------
// <auto-generated>
//     此代码由工具生成。
//     运行时版本:2.0.50727.3053
//
//     对此文件的更改可能会导致不正确的行为，并且如果
//     重新生成代码，这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using SharpNote.Core.Data;
using SharpNote.Core.Security;

namespace SharpNote.Core.Entity
{
	[TableInfoAttribute("UserInfo")]
	public class UserInfo : DbMappingObjectBase
	{
		#region

		private System.String _id = Guid.NewGuid ().ToString ();

		[FieldMapping(false, System.Data.DbType.String, false, true)]
		public System.String Id {
			get { return _id; }
			set { _id = value; }
		}

		private System.String _userName;

		[FieldMapping(true, System.Data.DbType.String, false, true)]
		public System.String UserName {
			get { return _userName; }
			set { _userName = value; }
		}

		private System.String _databaseFileName;

		[FieldMapping(false, System.Data.DbType.String, false, false)]
		public System.String DatabaseFileName {
			get { return _databaseFileName; }
			set { _databaseFileName = value; }
		}

		private System.Byte[] _signInPassword;

		[FieldMapping(false, System.Data.DbType.Binary, false, false)]
		public System.Byte[] SignInPassword {
			get { return _signInPassword; }
			set { _signInPassword = value; }
		}

		/*
		private System.Byte[] _dbPassword;

		[FieldMapping(false, System.Data.DbType.Binary, false, false)]
		public System.Byte[] DbPassword {
			get { return _dbPassword; }
			set { _dbPassword = value; }
		}
		*/

		private System.Byte[] _defaultKey;

		[FieldMapping(false, System.Data.DbType.Binary, false, false)]
		public System.Byte[] DefaultKey {
			get { return _defaultKey; }
			set { _defaultKey = value; }
		}

		private System.Byte[] _privateKey = new byte[0];

		[FieldMapping(false, System.Data.DbType.Binary, false, false)]
		public System.Byte[] PrivateKey {
			get { return _defaultKey; }
			set { _defaultKey = value; }
		}

		private System.Int64 _status = 1;

		[FieldMapping(false, System.Data.DbType.Int64, false, false)]
		public System.Int64 Status {
			get { return _status; }
			set { _status = value; }
		}

		private System.DateTime _createTime = DateTime.Now;

		[FieldMapping(false, System.Data.DbType.DateTime, false, false)]
		public System.DateTime CreateTime {
			get { return _createTime; }
			set { _createTime = value; }
		}


		#endregion

		#region Constructors

		public UserInfo ()
		{
		}

		#endregion

		#region Methods

		/// <summary>
		/// First of all, encryt the text param with StringEncryptionHelper.GetMD5HashBytes method, then compare with the password bytes.
		/// </summary>
		/// <param name="text">plain text to compare with the password.
		/// A <see cref="System.String"/>
		/// </param>
		/// <param name="privateKey">private key string for the method named StringEncryptionHelper.GetMD5HashBytes.
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>if each byte is equal.
		/// A <see cref="System.Boolean"/>
		/// </returns>
		public bool IsSignInPasswordEquals (string text)
		{
			if (_signInPassword == null || _signInPassword.Length == 0 || text == null) {
				return false;
			}

			byte[] encryptBytes = SharpNote.Core.Security.StringEncryptionHelper.GetMD5HashBytes (text);
			if (encryptBytes.Length != _signInPassword.Length) {
				return false;
			}

			for (int i = 0; i < encryptBytes.Length; i++) {
				if (_signInPassword[i] != encryptBytes[i]) {
					return false;
				}
			}

			return true;
		}

		/// <summary>
		///  Update Property: PrivateKey value. keyString is not allowed to be null. 
		///  (Note: When the value of SignInPassword property changed, you MUST invoke SetPrivateKey method to update the PrivateKey)
		/// </summary>
		/// <param name="plainTextSignInPassword">plain text password.
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="System.Boolean"/>
		/// </returns>
		public bool SetPrivateKey (string plainTextSignInPassword, string keyString)
		{
			if (keyString == null || plainTextSignInPassword == null) {
				return false;
			}
			if (!IsSignInPasswordEquals (plainTextSignInPassword)) {
				return false;
			}

			IKeySafe keySafe = new KeySafe ();

			//use the plain text sign in password as a private key to encrypt this PrivateKey.
			return keySafe.Encrypt (keyString, plainTextSignInPassword, out _privateKey);
		}

		/// <summary>
		/// Get the PrivteKey plain text. (Decrypt the PrivateKey value then return)
		/// </summary>
		/// <param name="privateKeyBytes">
		/// A <see cref="System.Byte[]"/>
		/// </param>
		/// <param name="plainTextPrivateKey">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="System.Boolean"/>
		/// </returns>
		public bool GetPrivateKeyPlainText (string plainTextSignInPassword, out string plainTextPrivateKey)
		{
			plainTextPrivateKey = string.Empty;
			if (_privateKey == null || _privateKey.Length == 0 || plainTextSignInPassword == null) {
				return false;
			}
			if (!IsSignInPasswordEquals (plainTextSignInPassword)) {
				return false;
			}

			IKeySafe keySafe = new KeySafe ();
			return keySafe.Decrypt (_privateKey, plainTextSignInPassword, out plainTextPrivateKey);
		}

		/// <summary>
		/// set Password property value(Encrypt with the decrypted value of Salt). 
		/// </summary>
		/// <param name="plaintextPassword">plaintext Password
		/// A <see cref="System.String"/>
		/// </param>
		public bool SetSignInPassword (string plaintextPassword)
		{
			if (plaintextPassword == null) {
				return false;
			}

			_signInPassword = StringEncryptionHelper.GetMD5HashBytes (plaintextPassword);

			return true;
		}

		public bool ChangeSignInPassword (string oldPlainTextPassword, string newPlainTextPassword)
		{
			if (oldPlainTextPassword == null || newPlainTextPassword == null) {
				return false;
			}
			if (!IsSignInPasswordEquals (oldPlainTextPassword)) {
				return false;
			}

			//Update sign in password.
			_signInPassword = StringEncryptionHelper.GetMD5HashBytes (newPlainTextPassword);

			//Update PrivateKey property value.
			string privateKeyPlainText = string.Empty;
			if (GetPrivateKeyPlainText (oldPlainTextPassword, out privateKeyPlainText)) {
				if (!SetPrivateKey (privateKeyPlainText, newPlainTextPassword)) {
					SetSignInPassword (oldPlainTextPassword);
				} else {
					return true;
				}
			} else {
				SetSignInPassword (oldPlainTextPassword);
				return false;
			}

			return false;
		}

		/*
		public bool SetDbPassword (string plainTextSignInPassword, string newPlaintextDbPassword)
		{
			if (newPlaintextDbPassword == null || plainTextSignInPassword == null) {
				return false;
			}
			if (!IsSignInPasswordEquals (plainTextSignInPassword)) {
				return false;
			}

			string saltString = string.Empty;
			if (!GetPrivateKeyPlainText (plainTextSignInPassword, out saltString)) {
				return false;
			}

			return StringEncryptionHelper.EncryptString (newPlaintextDbPassword, saltString, out _dbPassword);
		}

		public bool GetDbPassword (string plainTextSignInPassword, out string result)
		{
			result = string.Empty;
			if (plainTextSignInPassword == null) {
				return false;
			}
			if (!IsSignInPasswordEquals (plainTextSignInPassword)) {
				return false;
			}

			string saltString = string.Empty;
			if (!GetPrivateKeyPlainText (plainTextSignInPassword, out saltString)) {
				return false;
			}

			return StringEncryptionHelper.DecryptString (_dbPassword, saltString, out result);
		}
		*/

		public bool SetDefaultKey (string plainTextSignInPassword, string plaintextDefaultKeyString)
		{
			if (plainTextSignInPassword == null || plaintextDefaultKeyString == null) {
				return false;
			}
			if (!IsSignInPasswordEquals (plainTextSignInPassword)) {
				return false;
			}

			string saltString = string.Empty;
			if (!GetPrivateKeyPlainText (plainTextSignInPassword, out saltString)) {
				return false;
			}

			return StringEncryptionHelper.EncryptString (plaintextDefaultKeyString, saltString, out _defaultKey);
		}

		public bool GetDefaultKey (string plainTextSignInPassword, out string result)
		{
			result = string.Empty;
			if (plainTextSignInPassword == null) {
				return false;
			}
			if (!IsSignInPasswordEquals (plainTextSignInPassword)) {
				return false;
			}

			string saltString = string.Empty;
			if (!GetPrivateKeyPlainText (plainTextSignInPassword, out saltString)) {
				return false;
			}

			return StringEncryptionHelper.DecryptString (_defaultKey, saltString, out result);
		}

		/// <summary>
		/// Get UserInfo by user name. 
		/// </summary>
		/// <param name="userName">user name
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>UserInfo instance.
		/// A <see cref="UserInfo"/>
		/// </returns>
		public static UserInfo GetUserInfoByUserName (string userName)
		{
			if (string.IsNullOrEmpty (userName)) {
				return null;
			}

			bool isEmpty = true;
			return DbObjectMappingHelper.Query<UserInfo> ("select * from UserInfo where UserName = @userName", out isEmpty, DataAccessService.CreateDbParameter ("@userName", System.Data.DbType.String, userName));
		}

		/// <summary>
		/// Check if username already exists. 
		/// </summary>
		/// <param name="userName">user name
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>if already exists
		/// A <see cref="System.Boolean"/>
		/// </returns>
		public static bool Exists (string userName)
		{
			DataAccessService das = DataAccessService.GetDataAccessServiceInstance ();
			object value = das.ExecuteScalar ("select count(*) as FCount from UserInfo where UserName = @userName", System.Data.CommandType.Text, DataAccessService.CreateDbParameter ("@userName", System.Data.DbType.String, userName));
			return value != null && Convert.ToInt64 (value) > 0;
		}

		/// <summary>
		/// Create new user information and all of it's own stuff. 
		/// </summary>
		/// <param name="newUser">
		/// A <see cref="UserInfo"/>
		/// </param>
		/// <returns>
		/// A <see cref="System.Boolean"/>
		/// </returns>
		public static bool CreateNewUser (UserInfo newUser)
		{
			if (newUser == null) {
				return false;
			}

			if (string.IsNullOrEmpty (newUser.Id) || string.IsNullOrEmpty (newUser.UserName)) {
				return false;
			}
			if (UserInfo.Exists (newUser.UserName)) {
				return false;
			}

			bool createdSuccess = DbObjectMappingHelper.Create<UserInfo> (newUser);
			if (!createdSuccess) {
				return false;
			}

			//create user owned directory if not exists.
			string userFolder = System.IO.Path.Combine(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
			                                           "Data"), newUser.Id);
			if (!System.IO.Directory.Exists (userFolder)) {
				try {
					System.IO.Directory.CreateDirectory (userFolder);
				} catch (Exception ex) {
#if DEBUG
	throw ex;			
#endif
					return false;
				}
			}
			
			string dbFileName = string.Empty;
			
			if(!string.IsNullOrEmpty(newUser.DatabaseFileName))
			{
				dbFileName = System.IO.Path.Combine(userFolder,
			       newUser.DatabaseFileName);
			}else  //create new database file.
			{
				newUser.DatabaseFileName = newUser.Id + ".db";
				dbFileName = System.IO.Path.Combine(userFolder,
			       newUser.Id + ".db");
			}
			
			string connectionString = DataAccessService.BuildConnectionString(dbFileName, string.Empty);
			DataAccessService das = new DataAccessService(connectionString);
			if(das.CreateDatabaseIfNotExists())
			{
			    DatabaseBuilder dbBuilder = new DatabaseBuilder(connectionString);
				return dbBuilder.Build();
			}
			
			return false;
		}

		#endregion

	}


}
